/**************************************************************************************************
D I A G N O S T I C S   &   U T I L I T I E S
**************************************************************************************************/

/**
 * deTag() converts XML or HTML < and > tags into HTML-printable chars
 *
 * @param html is the HTML (or XML) to convert
 *
 * @return the detagged input
*/
function deTag(html) {
	return html.replace(/</gi, "&lt;").replace(/>/gi, "&gt;");
}


/**
 * printXML() prints the passed XML
 *
 * @param xml_obj is the XML object to print
*/
function printXML(xml_obj) {
	try {
		document.getElementById("output").innerHTML = "<h2>XML:</h2>" + deTag(XMLToString(xml_obj).replace(/>/gi, ">\n")).replace(/\n/gi, "<br>");
	} catch (e) { }
}


/**
 * XMLtoString() converts an XML object to a string
 *
 * @param xml_obj is the object to convert
 *
 * @return a string of the XML document
*/
function XMLToString(xml_obj) {

	// Text to return
	var text = false;

	// Try Gecko, Safari, Opera
	try {

		text = (new XMLSerializer()).serializeToString(xml_obj);

	} catch (e) {
		try {

			// Try IE
			text = xml_obj.xml;

		} catch (e) {
			alert("XMLToString(): " + e);
		}
	}

	return text;
}


/**
 * stringToXML() converts a string into an XML object (assuming the string contains valid XML)
 *
 * @param string is the string to convert
 *
 * @return an XML object
*/
function stringToXML(string) {

	var xml = false;

	try {
		xml = (new DOMParser()).parseFromString(string, "text/xml");
	} catch (e) {
		try {
			xml = new ActiveXObject("Microsoft.XMLDOM");
			xml.async = "false";
			xml.loadXML(string);
		} catch (e) {
			xml = false;
		}
	}

	return xml;
}


/**
 * getAttributes() gets all the attributes of an XML node as an key => value array
 *
 * @param node is an XML node
 *
 * @return an array of attribute names and values
*/
function getAttributes(node) {
	
	// Create array
	var attr = new Array();
	
	try {
	
		// Populate (Safari needs a full for loop, not just a for...in loop (Why?)
		for (var j = 0; j < node.attributes.length; j++) {
			
			
				if ("" + node.attributes[j].value != "undefined") {
					
					attr[node.attributes[j].name.toLowerCase()] = node.attributes[j].value;
				}
			
		}
	
	} catch (error) {
		alert("getAttributes(): " + error + "; node: " + node);
	}
	
	// Return
	return attr;
}


/**************************************************************************************************
H T T P   F U N C T I O N S
**************************************************************************************************/

// The HTTP object
var http;

/**
 * getHTTPObject() instantiates and returns an HTTP object
 *
 * @return a new HTTP object
*/
function getHTTPObject() {
	
	// Create Object
	var xmlhttp;
	
	// Try conditional statements
	/*@cc_on
	@if (@_jscript_version >= 5)
		try {
			xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (E) {
				xmlhttp = false;
			}
		}
	@else
		xmlhttp = false;
	@end @*/
	
	// If no good, try the old fashioned way
	if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
		try {
			xmlhttp = new XMLHttpRequest();
		} catch (e) {
			xmlhttp = false;
		}
	}

	// Return
	return xmlhttp;
}


/**
 * loadXML() loads the XML data into Javascript
 *
 * @param file_name is the filename to load
 * @param tree_box is the tree box to load into
*/
function loadTBXML(file_name, tree_box) {
	
	// Check file name
	file_name = file_name ? file_name : "page-list.xml";

	// Instantiate
	http = getHTTPObject();

	// Load form data
	http.open("GET", "assets/xml/" + file_name, true);

	// On change
	http.onreadystatechange = function() {
		loadedXML(tree_box);
	};

	// Send
	http.send(null);
}


/**
 * loadedXML() is called when the XML is loaded
 *
 * @param tree_box is the tree box to use
*/
function loadedXML(tree_box) {

	// Check response type
	if (http.readyState == 4) {

		// If IE, take the text response and convert to XML
		if (browser.isIE) {

			// Take text to the MAX
			var xml_text = http.responseText;

			// Run the XML DOM
			var xml = new ActiveXObject("Microsoft.XMLDOM");
			xml.async = "false";
			xml.loadXML(xml_text);

		} else {
		
			// Just get the XML out of the response
			var xml = http.responseXML;

		}

		// Store XML
		treeboxes[tree_box].xml = refreshXML(xml, tree_box);

		// Store original XML in list form for comparison on saving
		treeboxes[tree_box].orig_list = getXMLAsList(tree_box, true);
		
		// Set display mode
		treeboxes[tree_box].display_mode = "tree";
		
		// Get path to selected item
		treeboxes["exampletb"].selected_item_path = getItemPath(treeboxes["exampletb"].selected_item, tree_box);
		
		// Update Interface
		endSearch(tree_box);
		updateButtons(tree_box);

		// Print Tree
		printTreeXML(tree_box);
	}
}


/**************************************************************************************************
S T A N D - A L O N E   X M L   H A N D L I N G
**************************************************************************************************/


/**
 * refreshXML refreshes the existing XML, removing cruft and tidying up
 *
 * @param xml_obj is the XML object to use (optional)
 * @param tree_box is the ID of the tree box to use
 *
 * @return the XML object
*/
function refreshXML(xml_obj, tree_box) {
	
	// Get XML as a new string
	var str = exportXML(xml_obj, tree_box);

	// Convert back to XML
	return stringToXML(str);
}


/**
 * exportXML() recreates the existing XML as a string to export
 *
 * @param xml_obj is the XML object to use
 * @param tree_box is the Tree Box to use
 *
 * @return a string of XML
*/
function exportXML(xml_obj, tree_box) {
	
	// Create list with attributes
	treeboxes[tree_box].xml_str = "<?xml version=\"1.0\"?><list";
	var attr = getAttributes(xml_obj.getElementsByTagName("list")[0]);
	for (var i in attr) {
		//if (findInArray(invalid_xml_attr, i) == -1) {
			treeboxes[tree_box].xml_str += " " + i + "=\"" + attr[i] + "\"";
		//}
	}
	treeboxes[tree_box].xml_str += ">";
	
	// Get children
	var children = getItemChildrenOf(xml_obj.getElementsByTagName("list")[0]);
	
	// For each child
	for (var i = 0; i < children.length; i++) {
		exportXMLNode(children[i] ,tree_box);
	}
	
	// End list
	treeboxes[tree_box].xml_str += "</list>";
	
	// Return
	return treeboxes[tree_box].xml_str;
}


/**
 * exportXMLNode() regenerates the XML string of a node and it's children
 *
 * @param node is the XML node
 * @param tree_box is the tree box
*/
function exportXMLNode(node, tree_box) {
	
	// Get children
	var children = getItemChildrenOf(node);
	
	// Attributes
	treeboxes[tree_box].xml_str += "<item";
	var attr = getAttributes(node);
	for (var i in attr) {
		//if (findInArray(invalid_xml_attr, i) == -1) {
			treeboxes[tree_box].xml_str += " " + i + "=\"" + attr[i] + "\"";
		//}
	}
	
	// If children, show them now
	if (children.length > 0) {
		treeboxes[tree_box].xml_str += ">";
		//for (var i in children) {
		for (var i = 0; i < children.length; i++) {
			exportXMLNode(children[i], tree_box);
		}
		treeboxes[tree_box].xml_str += "</item>";
	} else {
		treeboxes[tree_box].xml_str += " />";
	}
}
